<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <!-- <script>
    // 常用版本
    /*
    Function.prototype.myCall = function (thisArg, ...arrs) {
      thisArg.f = this;
      const res = thisArg.f(...arrs);
      delete thisArg.f;
      return res;
    }

    function func(num1, num2) {
      console.log(this);
      console.log(num1, num2);
      return num1 + num2;
    }

    const student = {
      name: 'xiaowu'
    }

    console.log(func.myCall(student, 1, 2));
    */

    // 优化版本
    // 现在存在的问题，缺少边界判断，如果thisArg是null或者undefined，会报错
    // 如果thisArg本身就是一个函数，会导致this指向错误
    Function.prototype.myCall = function (thisArg, ...arrs) {
      const key = Symbol(); // 定义一个Symbol作为属性名，防止属性名冲突
      thisArg[key] = this; // 给thisArg添加属性，直接在thisArg上赋值函数，没有在全局对象上面赋值函数
      const res = thisArg[key](...arrs); // 执行函数，并获取返回值
      delete thisArg[key]; // 删除属性
      return res; // 解决返回值
    }

    const student = {
      name: 'xiaowu'
    }

    function func(num1, num2) {
      console.log(this);
      console.log(num1, num2);
      return num1 + num2;
    }

    console.log(func.myCall(student, 1, 2));
  </script> -->
  <!-- <script>
    function myCall(obj) {
      if (typeof this !== "function") return;

      let context = obj || window;
      let args = Array.prototype.slice.call(arguments, 1);
      context.fn = this;

      let result = context.fn(...args);
      delete context.fn;
      return result;

    }


    function myApply(obj, arr) {
      if (typeof this !== "function") return;

      let context = obj || window;
      let args = Array.prototype.slice.call(arguments, 1);
      context.fn = this;

      let result = arr === undefined ? context.fn() : context.fn(...arr);
      delete context.fn;
      return result;
    }


    function myBind(obj) {
      if (typeof this !== "function") return;
      let context = obj || window;
      let args = Array.prototype.slice.call(arguments, 1);
      let fn = this;
      return function Fn() {
        let bindArg = args.concat(Array.prototype.slice.call(arguments));
        return fn.apply(
          this instanceof Fn ? this : context,
          bindArg
        )
      }
    }
  </script> -->
  <script>
    Function.prototype.myCall = function (thisArg, ...arrs) {
      let _this = thisArg === null || thisArg === undefined || typeof thisArg === "function" ? window : thisArg;
      const key = Symbol();
      _this[key] = this;
      let result = _this[key](...arrs);
      delete _this[key];
      return result;
    }

    let obj = {
      name: "tom",
      fn: function () {
        console.log("this: ", this);
      }
    }

    function fun1() {
      console.log("this: ", this);
    }

    fun1.myCall(() => { });
  </script>
</body>

</html>